//
//	WindowFromPointEx.c
//
//  Copyright (c) 2002 by J Brown 
//  Freeware
//
//	HWND WindowFromPointEx(POINT pt)
//
//	Provides a better implementation of WindowFromPoint.
//  This function can return any window under the mouse,
//  including controls nested inside group-boxes, nested
//  dialogs etc.
//

#define STRICT
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <tchar.h>

static HWND  hwndGlobal;
static HWND  hwndButton;
static BOOL  g_fShowHidden;
static DWORD dwArea;

//
//	Callback function used with FindBestChild
//
static BOOL CALLBACK FindBestChildProc(HWND hwnd, LPARAM lParam)
{
	RECT  rect;
	DWORD a;
	POINT pt;

	pt.x = (short)LOWORD(lParam);
	pt.y = (short)HIWORD(lParam);

	GetWindowRect(hwnd, &rect);

	// Is the mouse inside this child window?
	if(PtInRect(&rect, pt))
	{
		// work out area of child window
		a = (rect.right-rect.left) * (rect.bottom-rect.top);
	
		// if this child window is smaller than the
		// current "best", then choose this one
		if(a < dwArea && (IsWindowVisible(hwnd) || g_fShowHidden == TRUE))
		{
			dwArea = a;
			hwndGlobal = hwnd;
		}
	}

	return TRUE;
}

//
//	The problem:
//
//	WindowFromPoint API is not very good. It cannot cope
//  with odd window arrangements, i.e. a group-box in a dialog
//  may contain a few check-boxes. These check-boxes are not
//  children of the groupbox, but are at the same "level" in the
//  window-hierachy. WindowFromPoint will just return the
//  first available window it finds which encompasses the mouse
//  (i.e. the group-box), but will NOT be able to detect the contents.
//
//	Solution:
//
//	We use WindowFromPoint to start us off, and then step back one
//  level (i.e. from the parent of what WindowFromPoint returned).
//
//	Once we have this window, we enumerate ALL children of this window
//  ourselves, and find the one that best fits under the mouse - 
//  the smallest window that fits, in fact.
//
//	I've tested this on alot of different apps, and it seems
//  to work flawlessly - in fact, I havn't found a situation yet
//  that this method doesn't work on.....we'll see!
//
//  Inputs:
//
//	hwndFound - window found with WindowFromPoint
//	pt        - coordinates of mouse, in screen coords
//				(i.e. same coords used with WindowFromPoint)
//
static HWND FindBestChild(HWND hwndFound, POINT pt)
{
	HWND  hwnd;
	DWORD dwStyle;

	dwArea = -1;	// Start off again

	hwndGlobal = 0;

	hwnd = GetParent(hwndFound);
	
	dwStyle = GetWindowLong(hwndFound, GWL_STYLE);

	// The original window might already be a top-level window,
	// so we don't want to start at *it's* parent
	if(hwnd == 0 || (dwStyle & WS_POPUP))
		hwnd = hwndFound;

	// Enumerate EVERY child window.
	//
	//	Note to reader:
	//
	//	You can get some real interesting effects if you set
	//  hwnd = GetDesktopWindow()
	//  fShowHidden = TRUE
	//  ...experiment!!
	//
	EnumChildWindows(hwnd, FindBestChildProc, MAKELPARAM(pt.x, pt.y));

	if(hwndGlobal == 0)
		hwndGlobal = hwnd;

	return hwndGlobal;
}

//
//	Find window under specified point (screen coordinates)
//
HWND WindowFromPointEx(POINT pt, BOOL fShowHidden)
{
	HWND hWndPoint;
	
	g_fShowHidden = fShowHidden;

	//
	// First of all find the parent window under the mouse
	// We are working in SCREEN coordinates	
	// 
	hWndPoint = WindowFromPoint(pt);
	
	if(hWndPoint == 0)
		return 0;

	// WindowFromPoint is not too accurate. There is quite likely
	// another window under the mouse.
	hWndPoint = FindBestChild(hWndPoint, pt);
	
	//if we don't allow hidden windows, then return the parent
	if(!g_fShowHidden)
	{
		while(hWndPoint && !IsWindowVisible(hWndPoint))
			hWndPoint = GetParent(hWndPoint);
	}

	return hWndPoint;
}

